/// @author  Alberto Franco
/// @file    barber_shop.go
/// @date    02-05-2011
/// @brief   This in the implementation of the barber shop problem as found in
///          "The Little Book of Semaphores" by Allen B. Downey 
///          Customer data structure
package barbershop

import (
    "sync"
    "fmt"
    "strconv"
)

var customerCount int = 0
var maxCustomers  int = 0
var mutex         *sync.Mutex = new(sync.Mutex)

/// Implements a customer. Customer enter into the shop and check if it can
/// sits down or get his hair cut. If not he came out of the shop.
/// Customer is a finite process. When he has finished he exit the shop and 
/// never returns.
/// <--- CCS DEFINITION ------------------------------------------------------->
/// C = EnterShop.(Sits.GetHairCut.ExitShop + GetHairCut.ExitShop + ExitShop)
type Customer struct {
    barber  *Barber   ///< Pointer to the barber 
    name    string    ///< name of the customer
    CutHair chan int  ///< Channel for the customer to cut hair 
}

/// Each customer enter the shop if the can he sits down
func (self *Customer) EnterShop() {
    /// Enter shop and sit down
    mutex.Lock() 
    if customerCount == maxCustomers {
        fmt.Println(self.name, "exit")
        /// No room available, exit the shop
        mutex.Unlock()
        return
    }
    /// Sit down
    customerCount += 1
    mutex.Unlock()
    /// Awake the barber
    self.barber.Chair <- self
    // wait for the signal of the barber
    <- self.CutHair 
    self.getHairCut()
    /// Release the chair
    mutex.Lock(); 
    customerCount -= 1
    mutex.Unlock()
}

/// Get the hair cut by the barber
func (self *Customer) getHairCut() {
    fmt.Println("Cut hair for ", self.name)
}

/// Create a given number of customers 
func CreateCustomers(barber *Barber, custNumber, maxCust int) []Customer {
    customers := make ([]Customer, custNumber)
    customerCount = 0
    maxCustomers = maxCust
    /// Init the customers
    for i := 0; i < custNumber; i++ {
        customers[i].name    = "Cust_" + strconv.Itoa(i)
        customers[i].barber  = barber
        customers[i].CutHair = make (chan int)
    }
    return customers
} 
